<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>NoiseBox - 噪声生成器</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }

        .container {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 20px;
            padding: 40px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
            max-width: 400px;
            width: 100%;
            backdrop-filter: blur(10px);
        }

        h1 {
            text-align: center;
            color: #333;
            margin-bottom: 30px;
            font-size: 28px;
            font-weight: 600;
        }

        .control-group {
            margin-bottom: 25px;
        }

        label {
            display: block;
            margin-bottom: 8px;
            color: #555;
            font-weight: 500;
            font-size: 14px;
        }

        select, input[type="range"] {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 8px;
            font-size: 16px;
            transition: all 0.3s ease;
        }

        select {
            background: white;
            cursor: pointer;
        }

        select:hover {
            border-color: #667eea;
        }

        input[type="range"] {
            -webkit-appearance: none;
            height: 6px;
            background: #ddd;
            outline: none;
            padding: 0;
        }

        input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 20px;
            height: 20px;
            background: #667eea;
            cursor: pointer;
            border-radius: 50%;
            transition: all 0.3s ease;
        }

        input[type="range"]::-webkit-slider-thumb:hover {
            transform: scale(1.2);
            background: #764ba2;
        }

        .volume-display {
            text-align: center;
            margin-top: 5px;
            color: #666;
            font-size: 14px;
        }

        .play-button {
            width: 100%;
            padding: 15px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            border-radius: 10px;
            font-size: 18px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
            margin-top: 30px;
        }

        .play-button:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }

        .play-button.playing {
            background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
        }

        .play-button:disabled {
            background: #ccc;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }

        .status {
            text-align: center;
            margin-top: 15px;
            color: #666;
            font-size: 14px;
        }

        .status.active {
            color: #667eea;
            font-weight: 600;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>🎵 NoiseBox</h1>
        
        <div class="control-group">
            <label for="noiseType">噪声类型</label>
            <select id="noiseType">
                <option value="white">白噪声</option>
                <option value="pink">粉噪声</option>
                <option value="brown">布朗噪声</option>
            </select>
        </div>

        <div class="control-group">
            <label for="volume">音量</label>
            <input type="range" id="volume" min="0" max="100" value="50">
            <div class="volume-display">50%</div>
        </div>

        <button class="play-button" id="playButton">开始播放</button>
        
        <div class="status" id="status">准备就绪</div>
    </div>

    <script>
        class NoiseGenerator {
            constructor() {
                this.audioContext = null;
                this.gainNode = null;
                this.noiseNode = null;
                this.isPlaying = false;
                this.noiseType = 'white';
                this.volume = 0.5;
            }

            async initAudio() {
                if (!this.audioContext) {
                    this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
                }
                
                if (this.audioContext.state === 'suspended') {
                    await this.audioContext.resume();
                }
            }

            createWhiteNoise() {
                const bufferSize = this.audioContext.sampleRate * 2;
                const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate);
                const output = buffer.getChannelData(0);
                
                for (let i = 0; i < bufferSize; i++) {
                    output[i] = Math.random() * 2 - 1;
                }
                
                return buffer;
            }

            createPinkNoise() {
                const bufferSize = this.audioContext.sampleRate * 2;
                const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate);
                const output = buffer.getChannelData(0);
                
                let b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0;
                
                for (let i = 0; i < bufferSize; i++) {
                    const white = Math.random() * 2 - 1;
                    b0 = 0.99886 * b0 + white * 0.0555179;
                    b1 = 0.99332 * b1 + white * 0.0750759;
                    b2 = 0.96900 * b2 + white * 0.1538520;
                    b3 = 0.86650 * b3 + white * 0.3104856;
                    b4 = 0.55000 * b4 + white * 0.5329522;
                    b5 = -0.7616 * b5 - white * 0.0168980;
                    output[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362;
                    output[i] *= 0.11;
                    b6 = white * 0.115926;
                }
                
                return buffer;
            }

            createBrownNoise() {
                const bufferSize = this.audioContext.sampleRate * 2;
                const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate);
                const output = buffer.getChannelData(0);
                
                let lastOut = 0.0;
                
                for (let i = 0; i < bufferSize; i++) {
                    const white = Math.random() * 2 - 1;
                    output[i] = (lastOut + (0.02 * white)) / 1.02;
                    lastOut = output[i];
                    output[i] *= 3.5;
                }
                
                return buffer;
            }

            createNoiseBuffer(type) {
                switch (type) {
                    case 'white':
                        return this.createWhiteNoise();
                    case 'pink':
                        return this.createPinkNoise();
                    case 'brown':
                        return this.createBrownNoise();
                    default:
                        return this.createWhiteNoise();
                }
            }

            async start() {
                if (this.isPlaying) return;
                
                await this.initAudio();
                
                this.noiseNode = this.audioContext.createBufferSource();
                const noiseBuffer = this.createNoiseBuffer(this.noiseType);
                this.noiseNode.buffer = noiseBuffer;
                this.noiseNode.loop = true;
                
                this.gainNode = this.audioContext.createGain();
                this.gainNode.gain.value = this.volume;
                
                this.noiseNode.connect(this.gainNode);
                this.gainNode.connect(this.audioContext.destination);
                
                this.noiseNode.start();
                this.isPlaying = true;
            }

            stop() {
                if (!this.isPlaying) return;
                
                if (this.noiseNode) {
                    this.noiseNode.stop();
                    this.noiseNode.disconnect();
                    this.noiseNode = null;
                }
                
                if (this.gainNode) {
                    this.gainNode.disconnect();
                    this.gainNode = null;
                }
                
                this.isPlaying = false;
            }

            setVolume(value) {
                this.volume = value;
                if (this.gainNode) {
                    this.gainNode.gain.value = value;
                }
            }

            setNoiseType(type) {
                this.noiseType = type;
                if (this.isPlaying) {
                    this.stop();
                    this.start();
                }
            }
        }

        // 初始化应用
        const noiseGenerator = new NoiseGenerator();
        const playButton = document.getElementById('playButton');
        const volumeSlider = document.getElementById('volume');
        const volumeDisplay = document.querySelector('.volume-display');
        const noiseTypeSelect = document.getElementById('noiseType');
        const status = document.getElementById('status');

        // 事件监听器
        playButton.addEventListener('click', async () => {
            if (noiseGenerator.isPlaying) {
                noiseGenerator.stop();
                playButton.textContent = '开始播放';
                playButton.classList.remove('playing');
                status.textContent = '已停止';
                status.classList.remove('active');
            } else {
                try {
                    await noiseGenerator.start();
                    playButton.textContent = '停止播放';
                    playButton.classList.add('playing');
                    status.textContent = '播放中...';
                    status.classList.add('active');
                } catch (error) {
                    console.error('启动音频失败:', error);
                    status.textContent = '启动失败，请重试';
                }
            }
        });

        volumeSlider.addEventListener('input', (e) => {
            const volume = e.target.value / 100;
            noiseGenerator.setVolume(volume);
            volumeDisplay.textContent = `${e.target.value}%`;
        });

        noiseTypeSelect.addEventListener('change', (e) => {
            noiseGenerator.setNoiseType(e.target.value);
            if (noiseGenerator.isPlaying) {
                status.textContent = `正在播放 ${e.target.options[e.target.selectedIndex].text}`;
            }
        });

        // 初始化显示
        volumeDisplay.textContent = `${volumeSlider.value}%`;
    </script>
</body>
</html>
